package com.manager.commons.utils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.manager.commons.annotation.Module;
import com.manager.commons.annotation.Operation;
import com.manager.core.module.manager.dao.ModuleSettingDao;
import com.manager.gen.InitLoad;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.annotation.PostConstruct;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 模块工具类
 */
@Component
public class ModuleUtil {
    public static final Logger log = LoggerFactory.getLogger(ModuleUtil.class);
    @Autowired
    private ModuleSettingDao dao;
    public static ModuleUtil moduleUtil;

    @PostConstruct
    public void init() {
        moduleUtil = this;
        moduleUtil.dao = this.dao;
    }

    public static void loadJsonConfig(String packageName) {
        //通过JSON文件加载模块组
        try {
            InputStream in = InitLoad.class.getClassLoader().getResourceAsStream("menu.json");
            String str = IOUtils.toString(in, StandardCharsets.UTF_8);
            JSONObject object = JSON.parseObject(str);
            log.debug("----------加载配置文件成功[menu.json]----------");
            log.debug(object.toJSONString());
            boolean init_module = object.getBoolean("INIT_MODULE");
            if (init_module) {
                initGroup(object);
                ModuleUtil.initModule("com.manager.core.module.manager.controller");
                ModuleUtil.initModule(packageName);
                log.debug("----------模块配置成功[Model]----------");
            }

        } catch (IOException e) {
            log.debug("----------加载配置文件失败[]----------");
        }

    }

    private static void initGroup(JSONObject object) {
        JSONArray array = object.getJSONArray("MENUS");
        initGroup(array, null);
        log.debug("初始化模块组:" + array.toJSONString());

    }

    private static void initGroup(JSONArray array, JSONObject object) {
        for (int i = 0; i < array.size(); i++) {
            JSONObject group = array.getJSONObject(i);
            Map<String, Object> map = new HashMap<>();
            map.put("pp_code", group.getString("code"));
            if (object != null && object.containsKey("code")) {
                map.put("pp_parent", object.getString("code"));
            }
            map.put("pp_name", group.getString("title"));
            map.put("pp_sort", group.getString("sort"));
            map.put("pp_icon", group.getString("icon"));
            map.put("pp_type", "MENU");
            //计算层级
            int level = object == null ? 1 : object.getIntValue("level") + 1;
            group.put("level", level);
            if (group.containsKey("show")) {
                map.put("pp_display", group.getString("show"));
            } else {
                map.put("pp_display", 1);
            }
            map.put("pp_sub", 1);
            map.put("pp_level", level);
            upsertMap(map);
            if (group.containsKey("sub") && !group.getJSONArray("sub").isEmpty()) {
                initGroup(group.getJSONArray("sub"), group);
            }
        }

    }

    private static void initModule(String packageName) {
        try {
            List<String> classNames = new ArrayList<String>();
            //扫描平台模块
            classNames.addAll(ClassScanUtil.getClassName(packageName, true));
            for (String moduleClass : classNames) {
                Class<?> clazz = Class.forName(moduleClass);
                //获取Controller注解
                if (clazz.isAnnotationPresent(Module.class)) {
                    Module module = clazz.getAnnotation(Module.class);
                    String code = module.code().replace("/", "-");
                    if (code.startsWith("/") || code.startsWith("-")) {
                        code = code.substring(1);
                    }
                    code = StringUtil.urlParam(code);
                    if (StringUtil.isNotEmpty(code)) {
                        //判断是否有父级 标签
                        Map<String, Object> map = new HashMap<>();

                        map.put("pp_code", code.replace("-*",""));
                        map.put("pp_parent", module.parent());
                        map.put("pp_name", module.title());
                        map.put("pp_icon", module.icon());
                        map.put("pp_sort", module.sort());
                        if (StringUtil.isNotEmpty(module.type())) {
                            map.put("pp_type", module.type());
                        } else {
                            map.put("pp_type", "MENU");
                        }

                        if (StringUtil.isNotEmpty(module.url())) {
                            String moduleUrl = module.url();
                            map.put("pp_path", moduleUrl);
                            map.put("pp_auth", moduleUrl.replace("/", ":"));
                        } else {
                            map.put("pp_path", StringUtil.urlParam(module.code()) + "/index");
                            map.put("pp_auth", code.replace("-", ":") + ":index");
                        }
                        map.put("pp_sub", 0);
                        map.put("pp_remark", module.description());
                        map.put("pp_display", module.show());
                        upsertMap(map);
                    }
                    Method[] methods = clazz.getMethods();
                    for (Method method : methods) {
                        String opath = "";
                        if (method.isAnnotationPresent(Operation.class)) {
                            Operation operation = method.getAnnotation(Operation.class);
                            if (method.isAnnotationPresent(RequestMapping.class)) {
                                RequestMapping orm = method.getAnnotation(RequestMapping.class);
                                opath = orm.value()[0];
                            } else if (method.isAnnotationPresent(PostMapping.class)) {
                                PostMapping orm = method.getAnnotation(PostMapping.class);
                                opath = orm.value()[0];
                            } else if (method.isAnnotationPresent(GetMapping.class)) {
                                GetMapping orm = method.getAnnotation(GetMapping.class);
                                opath = orm.value()[0];
                            }
                            if (opath.startsWith("/") || opath.startsWith("-")) {
                                opath = opath.substring(1);
                            }
                            opath = StringUtil.urlParam(opath);
                            if (StringUtil.isNotEmpty(opath) && !opath.equals("/")) {
                                Map<String, Object> map = new HashMap<>();
                                map.put("pp_code", opath.replace("/", "-").replace("-*",""));
                                map.put("pp_parent", code);
                                map.put("pp_name", module.title() + "-" + operation.title());
                                map.put("pp_auth", opath.replace("/", ":"));
                                map.put("pp_sort", operation.sort());
                                map.put("pp_display", operation.show());
                                if (StringUtil.isNotEmpty(operation.type())) {
                                    map.put("pp_type", operation.type());
                                } else {
                                    map.put("pp_type", "BUTTON");
                                }
//                                if (StringUtil.isNotEmpty(operation.url())) {
//
//                                    map.put("pp_path", operation.url());
//                                } else {
//                                    map.put("pp_path", opath);
//                                }
                                map.put("pp_display", operation.show());
                                upsertMap(map);
                            }

                        }

                    }
                }
            }
        } catch (ClassNotFoundException e) {
        }
    }

    private static void upsertMap(Map<String, Object> map) {
        moduleUtil.dao.upsertMap(map);
    }
}
